package com.example.kaogong.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.kaogong.common.exception.NotExistException;
import com.example.kaogong.common.utils.JwtUtil;
import com.example.kaogong.common.utils.RespBean;
import com.example.kaogong.sys.mapper.RoleMapper;
import com.example.kaogong.sys.mapper.StudentMapper;
import com.example.kaogong.sys.mapper.TeacherMapper;
import com.example.kaogong.sys.pojo.Student;
import com.example.kaogong.sys.pojo.Teacher;
import com.example.kaogong.sys.pojo.User;
import com.example.kaogong.sys.mapper.UserMapper;
import com.example.kaogong.sys.pojo.dto.RegisterDto;
import com.example.kaogong.sys.pojo.dto.ResetPasswordDto;
import com.example.kaogong.sys.pojo.dto.UserInfoUpdateDto;
import com.example.kaogong.sys.pojo.vo.UserInfoVo;
import com.example.kaogong.sys.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiniu.util.StringUtils;
import javassist.NotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author    
 * @since 2022-03-26
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private TeacherMapper teacherMapper;

    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtUtil jwtUtil;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Value("${qiniu.url}")
    private String urlHead;

    /**
     * 根据用户名获取用户信息
     * @param username 用户名
     * @return
     */
    @Override
    public User getUserInfoByUsername(String username) {
        User user = null;
        try {
            user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return user;
    }

    @Override
    public RespBean login(String username, String password) {
        //登录判断
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if (userDetails == null || !passwordEncoder.matches(password, userDetails.getPassword())) {
            return RespBean.error("用户名或密码不正确");
        }
        if (!userDetails.isEnabled()) {
            return RespBean.error("账号被禁用，请联系管理员");
        }
        UsernamePasswordAuthenticationToken authenticationToken = new
                UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //返回token
        String token = jwtUtil.generateToken(userDetails);
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("token", token);
        tokenMap.put("tokenHead", tokenHead);
        return RespBean.success("登录成功", tokenMap);
    }

    /**
     * 获取用户基本信息
     * @param name 用户名
     * @return
     */
    @Override
    public RespBean<UserInfoVo> getUserInfo(String name) {

        try {
            // 根据用户名查询用户信息
            User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", name));
            if (user == null)
                throw new NotExistException("用户不存在");

            // 设置用户名
            UserInfoVo userInfoVo = new UserInfoVo();
            userInfoVo.setUsername(user.getUsername());
            userInfoVo.setAvatar(urlHead + user.getUserImg());
            userInfoVo.setUid(user.getUid());

            if (user.getRoleId() != null)
                this.setUserInfoByRoleId(userInfoVo, user.getUid(), user.getRoleId());

            return RespBean.success(userInfoVo);
        } catch (NotExistException e) {
            e.printStackTrace();
        }
        return RespBean.error();
    }

    /**
     * 判断用户名是否存在
     * @param username 用户名
     * @return
     */
    @Override
    public RespBean judgeUsernameExist(String username) {
        try {
            Integer cnt = userMapper.selectCount(new QueryWrapper<User>().eq("username", username));
            if (cnt < 1)
                return RespBean.success("用户名不存在");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return RespBean.error("用户名已存在");
    }

    /**
     * 用户注册
     * @param registerDto 用户注册传输对象
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RespBean userRegister(RegisterDto registerDto) {
        // 插入用户信息并返回uid
        Integer uid = this.insertUser(registerDto);
        if (uid == null)
            return RespBean.error("用户注册失败");

        boolean insertUserInfo = this.insertUserInfoByRoleId(registerDto, uid);
        if (!insertUserInfo) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return RespBean.error("用户注册失败");
        }
        return RespBean.success("用户注册成功");
    }

    /**
     * 修改当前用户密码
     * @param passwordDto
     * @param name 用户名
     * @return
     */
    @Override
    public RespBean resetPassword(ResetPasswordDto passwordDto, String name) {
        try {
            // 查询当前用户信息
            User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", name));
            if (user == null || user.getDeleted())
                return RespBean.error("用户不存在");
            boolean matches = passwordEncoder.matches(passwordDto.getOldPassword(), user.getPassword());
            if (!matches)
                return RespBean.error("修改密码失败，旧密码不匹配");

            if (passwordDto.getNewPassword().equals(passwordDto.getOldPassword()))
                return RespBean.error("修改密码失败，旧密码与新密码相同");

            // 修改密码
            User newUser = new User(null, null, null, passwordEncoder.encode(passwordDto.getNewPassword()), null, null);
            int update = userMapper.update(newUser, new UpdateWrapper<User>().eq("uid", user.getUid()));
            if (update >= 1)
                return RespBean.success();

        } catch (Exception e) {
            e.printStackTrace();
        }

        return RespBean.error();
    }

    /**
     * 修改当前登录用户基本信息
     * @param userInfoUpdateDto
     * @param name
     * @return
     */
    @Override
    public RespBean updateCurrentUserInfo(UserInfoUpdateDto userInfoUpdateDto, String name) {
        try {
            User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", name));
            if (user == null || user.getDeleted())
                return RespBean.error("用户不存在");
            if (user.getRoleId() == 1)
                return RespBean.error("管理员无个人基本信息");

            boolean update = this.updateUserInfoByUid(user.getUid(), user.getRoleId(), userInfoUpdateDto);
            if (update)
                return RespBean.success();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return RespBean.error("修改个人信息失败");
    }

    /**
     * 修改当前用户头像
     * @param fileName 文件名
     * @param name 用户名
     * @return
     */
    @Override
    public RespBean updateUserAvatar(String fileName, String name) {
        try {
            int update = userMapper.updateUserAvatar(fileName, name);
            if (update >= 1)
                return RespBean.success();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return RespBean.error();
    }

    // 根据用户角色修改用户基本信息
    private boolean updateUserInfoByUid(Integer uid, Integer roleId, UserInfoUpdateDto userInfoUpdateDto) {
        try {
            if (roleId == 2) {
                Teacher teacher = new Teacher();
                teacher.setName(userInfoUpdateDto.getName());
                teacher.setTel(userInfoUpdateDto.getTel());
                teacher.setGender(userInfoUpdateDto.getGender());
                teacher.setAge(userInfoUpdateDto.getAge());
                teacher.setAddress(userInfoUpdateDto.getAddress());

                int update = teacherMapper.update(teacher, new UpdateWrapper<Teacher>().eq("uid", uid));
                if (update >= 1)
                    return true;
            }

            if (roleId == 3) {
                Student student = new Student();
                student.setName(userInfoUpdateDto.getName());
                student.setTel(userInfoUpdateDto.getTel());
                student.setGender(userInfoUpdateDto.getGender());
                student.setAge(userInfoUpdateDto.getAge());
                student.setAddress(userInfoUpdateDto.getAddress());
                int update = studentMapper.update(student, new UpdateWrapper<Student>().eq("uid", uid));
                if (update >= 1)
                    return true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 根据角色编号插入注册用户基本信息
     * @param registerDto 用户注册传输对象
     * @param uid 用户编号
     * @return
     */
    private boolean insertUserInfoByRoleId(RegisterDto registerDto, Integer uid) {
        try {
            // 注册对象为教师
            if (registerDto.getRoleId() == 2) {
                // new Teacher对象
                Teacher teacher = new Teacher();
                teacher.setUid(uid);
                teacher.setAddress(registerDto.getAddress());
                teacher.setAge(registerDto.getAge());
                teacher.setGender(registerDto.getGender());
                teacher.setName(registerDto.getName());
                teacher.setTel(registerDto.getTel());
                teacher.setPostId(registerDto.getPostId());

                // 教师信息持久化
                int insertTeacher = teacherMapper.insert(teacher);
                if (insertTeacher >= 1)
                    return true;
            }

            // 注册对象为学生
            if (registerDto.getRoleId() == 3) {
                // new Student对象
                Student student = new Student();
                student.setUid(uid);
                student.setAddress(registerDto.getAddress());
                student.setAge(registerDto.getAge());
                student.setGender(registerDto.getGender());
                student.setName(registerDto.getName());
                student.setTel(registerDto.getTel());

                // 学生信息持久化
                int insertStudent = studentMapper.insert(student);
                if (insertStudent >= 1)
                    return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 插入用户信息并返回uid
     * @param registerDto 用户注册传输对象
     * @return
     */
    private Integer insertUser(RegisterDto registerDto) {
        try {
            // new User对象
            User user = new User();
            user.setUsername(registerDto.getUsername());
            user.setUserImg("avatar/default.jpg");
            user.setRoleId(registerDto.getRoleId());
            user.setPassword(passwordEncoder.encode(registerDto.getPassword()));
            // User对象持久化
            int insert = userMapper.insert(user);

            // 如果插入成功，返回uid
            if (insert >= 1) {
                User insertUser = userMapper.selectOne(new QueryWrapper<User>().eq("username", registerDto.getUsername()));
                return insertUser.getUid();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据用户角色编号set用户基本信息 (因为只有三个角色，就直接硬编码了)
     * @param userInfoVo  用户基本信息前端视图对象
     * @param uid 用户编号
     * @param roleId 角色编号
     */
    private void setUserInfoByRoleId(UserInfoVo userInfoVo, Integer uid, Integer roleId) {
        if (roleId == 1) {
            userInfoVo.setRoleName("管理员");
            return;
        }

        if (roleId == 2) {
            userInfoVo.setRoleName("教师");
            Teacher teacher = teacherMapper.selectOne(new QueryWrapper<Teacher>().eq("uid", uid));
            if (teacher == null)
                return;

            userInfoVo.setName(teacher.getName());
            userInfoVo.setAge(teacher.getAge());
            userInfoVo.setAddress(teacher.getAddress());
            userInfoVo.setGender(teacher.getGender());
            userInfoVo.setTel(teacher.getTel());
        }

        if (roleId == 3) {
            userInfoVo.setRoleName("学生");
            Student student = studentMapper.selectOne(new QueryWrapper<Student>().eq("uid", uid));
            if (student == null)
                return;

            userInfoVo.setName(student.getName());
            userInfoVo.setAge(student.getAge());
            userInfoVo.setAddress(student.getAddress());
            userInfoVo.setGender(student.getGender());
            userInfoVo.setTel(student.getTel());
        }
    }
}
